<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<style>
		body {
			padding: 0;
			margin: 0;
			background-color: #222;
		}
	</style>
	<body>
		<canvas style="position: fixed;top: 0px;pointer-events: none;"></canvas>
	</body>
	<script src="../js二三事/jquery/js/jquery.js"></script>
	<script>
		if (window.location.href.indexOf('play') < 0) {
			class Vector2 {
				constructor(x = 0, y = 0) {
					this.x = x;
					this.y = y;
				}

				add(v) {
					this.x += v.x;
					this.y += v.y;
					return this;
				}

				multiplyScalar(s) {
					this.x *= s;
					this.y *= s;
					return this;
				}

				clone() {
					return new Vector2(this.x, this.y);
				}
			}


			class Time {
				constructor() {
					const now = Time.now();

					this.delta = 0;
					this.elapsed = 0;
					this.start = now;
					this.previous = now;
				}

				update() {
					const now = Time.now();

					this.delta = now - this.previous;
					this.elapsed = now - this.start;
					this.previous = now;
				}

				static now() {
					return Date.now() / 1000;
				}
			}


			class Particle {
				constructor(position, velocity = new Vector2(), color = 'white', radius = 1, lifetime = 1, mass = 1) {
					this.position = position;
					this.velocity = velocity;
					this.color = color;
					this.radius = radius;
					this.lifetime = lifetime;
					this.mass = mass;

					this.isInCanvas = true;
					this.createdOn = Time.now();
				}

				update(time) {
					if (!this.getRemainingLifetime()) {
						return;
					}

					this.velocity.add(Particle.GRAVITATION.clone().multiplyScalar(this.mass));
					this.position.add(this.velocity.clone().multiplyScalar(time.delta));
				}

				render(canvas, context) {
					const remainingLifetime = this.getRemainingLifetime();

					if (!remainingLifetime) return;

					const radius = this.radius * remainingLifetime;

					context.globalAlpha = remainingLifetime;
					context.globalCompositeOperation = 'lighter';
					context.fillStyle = this.color;

					context.beginPath();
					context.arc(this.position.x, this.position.y, radius, 0, Math.PI * 2);
					context.fill();
				}

				getRemainingLifetime() {
					const elapsedLifetime = Time.now() - this.createdOn;
					return Math.max(0, this.lifetime - elapsedLifetime) / this.lifetime;
				}
			}


			Particle.GRAVITATION = new Vector2(0, 9.81);

			class Trail extends Particle {
				constructor(childFactory, position, velocity = new Vector2(), lifetime = 1, mass = 1) {
					super(position, velocity);

					this.childFactory = childFactory;
					this.children = [];
					this.lifetime = lifetime;
					this.mass = mass;

					this.isAlive = true;
				}

				update(time) {
					super.update(time);

					// Add a new child on every frame
					if (this.isAlive && this.getRemainingLifetime()) {
						this.children.push(this.childFactory(this));
					}

					// Remove particles that are dead
					this.children = this.children.filter(function(child) {
						if (child instanceof Trail) {
							return child.isAlive;
						}

						return child.getRemainingLifetime();
					});

					// Kill trail if all particles fade away
					if (!this.children.length) {
						this.isAlive = false;
					}

					// Update particles
					this.children.forEach(function(child) {
						child.update(time);
					});
				}

				render(canvas, context) {
					// Render all children
					this.children.forEach(function(child) {
						child.render(canvas, context);
					});
				}
			}


			class Rocket extends Trail {
				constructor(childFactory, explosionFactory, position, velocity = new Vector2()) {
					super(childFactory, position, velocity);

					this.explosionFactory = explosionFactory;
					this.lifetime = 10;
				}

				update(time) {
					if (this.getRemainingLifetime() && this.velocity.y > 0) {
						this.explosionFactory(this);
						this.lifetime = 0;
					}

					super.update(time);
				}
			}


			const canvas = document.createElement('canvas');
			const context = canvas.getContext('2d');
			const time = new Time();
			let rockets = [];

			const getTrustParticleFactory = function(baseHue) {
				function getColor() {
					const hue = Math.floor(Math.random() * 15 + 30);
					return `hsl(${hue}, 100%, 75%`;
				}

				return function(parent) {
					const position = this.position.clone();
					const velocity = this.velocity.clone().multiplyScalar(-.1);
					velocity.x += (Math.random() - .5) * 8;
					const color = getColor();
					const radius = 1 + Math.random();
					const lifetime = .5 + Math.random() * .5;
					const mass = .01;

					return new Particle(position, velocity, color, radius, lifetime, mass);
				};
			};

			const getExplosionFactory = function(baseHue) {
				function getColor() {
					const hue = Math.floor(baseHue + Math.random() * 15) % 360;
					const lightness = Math.floor(Math.pow(Math.random(), 2) * 50 + 50);
					return `hsl(${hue}, 100%, ${lightness}%`;
				}

				function getChildFactory() {
					return function(parent) {
						const direction = Math.random() * Math.PI * 2;
						const force = 8;
						const velocity = new Vector2(Math.cos(direction) * force, Math.sin(direction) * force);
						const color = getColor();
						const radius = 1 + Math.random();
						const lifetime = 1;
						const mass = .1;

						return new Particle(parent.position.clone(), velocity, color, radius, lifetime, mass);
					};
				}

				function getTrail(position) {
					const direction = Math.random() * Math.PI * 2;
					const force = Math.random() * 128;
					const velocity = new Vector2(Math.cos(direction) * force, Math.sin(direction) * force);
					const lifetime = .5 + Math.random();
					const mass = .075;

					return new Trail(getChildFactory(), position, velocity, lifetime, mass);
				}

				return function(parent) {
					let trails = 32;
					while (trails--) {
						parent.children.push(getTrail(parent.position.clone()));
					}
				};
			};

			const addRocket = function() {
				const trustParticleFactory = getTrustParticleFactory();
				const explosionFactory = getExplosionFactory(Math.random() * 360);

				const position = new Vector2(Math.random() * canvas.width, canvas.height);
				const thrust = window.innerHeight * .75;
				const angle = Math.PI / -2 + (Math.random() - .5) * Math.PI / 8;
				const velocity = new Vector2(Math.cos(angle) * thrust, Math.sin(angle) * thrust);
				const lifetime = 3;

				rockets.push(new Rocket(trustParticleFactory, explosionFactory, position, velocity, lifetime));

				rockets = rockets.filter(function(rocket) {
					return rocket.isAlive;
				});
			};

			const render = function() {
				requestAnimationFrame(render);

				time.update();
				context.clearRect(0, 0, canvas.width, canvas.height);

				rockets.forEach(function(rocket) {
					rocket.update(time);
					rocket.render(canvas, context);
				});
			};

			const resize = function() {
				canvas.height = window.innerHeight;
				canvas.width = window.innerWidth;
			};

			$(function() {
				canvas.style.position = 'fixed';
				canvas.style.top = '0';
				canvas.style.pointerEvents = 'none';
				canvas.onclick = addRocket;
				document.body.onclick = addRocket;
				document.body.appendChild(canvas);

				window.onresize = resize;
				resize();

				setInterval(addRocket, 1000);
				render();
			});
		}
	</script>
</html>
